<?php

namespace Lib\Db;

use Lib\Base\Common;
use Lib\Base\Request;
use Lib\Service\TGLog;

abstract class Db
{
    protected $config;

    protected $groupId = 0;
    protected $instanceId = 0;

    protected $timeout = 3;

    protected $dbLink;
    protected $errorInfo;

    abstract protected function initConfig();
    abstract protected function connectDb();
    abstract protected function execQuery($sql);
    abstract protected function execUpdate($sql);
    abstract protected function execTrans($sqlArr);
    /**
     * 写日志
     */
    protected function writeLog($errno, $error, $data = '')
    {
        $this->errorInfo = [
            'errno' => $errno,
            'error' => $error,
            'data' => $data
        ];
        recordLog('Query Log:' . json_encode($this->errorInfo), __FILE__, __LINE__, LP_INFO);
    }

    /**
     * 返回错误信息
     */
    public function getError()
    {
        return $this->errorInfo;
    }

    /**
     * 获取配置文件
     */
    protected function getConfig(array $dbCon = [])
    {
        if (empty($dbCon) && defined('DB_CONFIG')) {
            $dbCon = DB_CONFIG;
        }
        $groupNum = count($dbCon);
        for ($i = 0; $i < $groupNum; $i++) {
            $instanceList = explode('|', $dbCon['DB_GROUP_' . $i]['instanceName']);
            $dbNameList = explode('|', $dbCon['DB_GROUP_' . $i]['databaseName']);
            $instanceNum = count($instanceList);

            for ($j = 0; $j < $instanceNum; $j++) {
                $this->config[$i][$j]['instanceName'] = $instanceList[$j];
                $this->config[$i][$j]['dbName'] = $dbNameList[$j] ?? $dbNameList[0];
                $this->config[$i][$j]['userName'] = $dbCon['DB_GROUP_' . $i]['userName'] ?? '';
                $this->config[$i][$j]['password'] =  $dbCon['DB_GROUP_' . $i]['password'] ?? '';
            }
        }
    }

    /**
     * 解析实例信息
     */
    protected function initInstanceId($config)
    {
        if (isset($config['groupId']) && !empty($config['groupId'])) {
            $this->groupId = $config['groupId'];
        }

        if (isset($config['shardId']) && isset($config['shardNum']) && !empty($config['shardId']) && !empty($config['shardNum'])) {
            if (preg_match('/^[1-9]\d*$/', $config['shardId'])) {
                $this->instanceId = fmod($config['shardId'], $config['shardNum']);
            } else {
                $hashNum = Common::time33($config['shardId']);
                $hashNum = abs($hashNum);
                $this->instanceId = fmod($hashNum, $config['shardNum']);
            }
        } else if (isset($config['instanceId']) && !empty($config['instanceId'])) {
            $this->instanceId = $config['instanceId'];
        }
    }

    /**
     * proxy异常上报
     * @param int $error 错误码
     */
    protected function tglogReport($error)
    {
        if (RUN_ENV == 'ulink' && ENV != 'test') {
            $dbConfig = $this->config[$this->groupId][$this->instanceId];
            $apiName = Request::param('route') ? Request::param('route') : (Request::param('c') . '/' . Request::param('a'));
            $data = [
                ULINK_SAPPID,               //sAppid
                Request::param('game'),     //sAppKey
                Request::param('iActId'),   //活动ID
                Request::param('openid'),   //openid
                PROXY_CONNECT_ERROR,         //错误码
                'db连接异常，host：' . $dbConfig['host'] . '，port：' . $dbConfig['port'] . '，dbName：' . $dbConfig['dbName'] . '，error：' . $error,                      //错误内容
                Request::serverParam('SERVER_ADDR'),    //服务器ID
                Request::getParam('sAmsSerial'),        //流水号
                date('Y-m-d H:i:s'),        //时间
                '',
                '',
                '',
                $apiName  //sApiName
            ];
            $tglog = new TGLog(TGLOG_SERVER_INFO);
            $tglog->setTbName('UlinkVitalError');
            $tglog->sendLog($data);
        }
    }

    public function getShardingInfo()
    {
        return ['groupId' => $this->groupId, 'instanceId' => $this->instanceId];
    }
}
